#pragma once

#include <cmath>
#include <algorithm>

#include "Context.h"
#include "UnitGroup.h"
#include "Formation.h"

#include "PlatoonStates.h"

#include "EnemyManager.h"

class Platoon : public Context
{
public:
	Platoon(BWAPI::Player* player = BWAPI::Broodwar->self());
	Platoon(UnitGroup units, BWAPI::Player* player = BWAPI::Broodwar->self());
	Platoon(const std::set<BWAPI::Unit*> units, BWAPI::Player* player = BWAPI::Broodwar->self());

	static const int DRAGOON_SPEED = 5; // real value 5.25
	static const int DRAGOON_COOLDOWN = 30; //frames
	static const int DRAGOON_ATTACK = 20;
	static const int DRAGOON_RANGE = 128;

	// Context|FSM methods
	virtual void request();

	// Movement methods
	void move(BWAPI::Position targetPosition, bool relativePosition = false);
	void attack(BWAPI::Unit* target);
	void attack(BWAPI::Position target, bool relativePosition = false);
	void stop();

	bool isUnitMoving();

	// Formation methods (simple delegate to Formation class)
	void goLineFormation(double facingAngle, int innerDistance = Formation::DEFAULT_INNER_DISTANCE);
	void goBoxFormation(double facingAngle, int width, int length, int innerDistance = Formation::DEFAULT_INNER_DISTANCE);
	void goCircleFormation(double facingAngle, int radius, int innerDistance = Formation::DEFAULT_INNER_DISTANCE);

	void rotateFormation(double facingAngle, BWAPI::Position anchor = BWAPI::Position(0, 0));

	bool hasSpaceForFormation(Formation::Type type) { return mFormation.hasSpaceForFormation(type); }

	// Battle methods
	int calculatePossibleAttackers(BWAPI::Unit* target);
	std::pair<int,int> calculateAlliesAttackers(BWAPI::Unit* target, EnemyManager* enemy);
	double calculateAttackFactor(BWAPI::Unit* target, EnemyManager* enemy);
	BWAPI::Unit* getBestTarget(EnemyManager* enemy);

	// Unit management methods
	void unitShowed(BWAPI::Unit* unit);
	void unitDiscovered(BWAPI::Unit* unit);
	void unitEvaded(BWAPI::Unit* unit);
	void unitDestroyed(BWAPI::Unit* unit);
	void unitCreated(BWAPI::Unit* unit);

	// Debug methods
	void drawDebug();
	void drawUnderAttackLine(BWAPI::Unit* unit);// draw enemies' target lines
	void drawTargetLine(BWAPI::Unit* unit);		// draw target line for each unit
	void drawWeaponCooldown(BWAPI::Unit* unit);	// draw each unit's weapon cooldown

	// GAMBI
	BWAPI::Position getCenter() { return mUnits.getCenter(); }
	UnitGroup& getUnits() { return mUnits; }
	
private:
	UnitGroup mUnits;
	Formation mFormation;

	BWAPI::Player* mPlayer;

	void initialize();
};
